#include "include/vesa.h"
#include "include/mm.h"
#include "include/string.h"
#include "include/sched.h"

struct vesa_mode_info* vesa_mode_info;

void vesa_init() {
  /*
  * Load VESA mode information stored in the real mode area into the 64 bit mode area
  */
  vesa_mode_info = malloc(sizeof(struct vesa_mode_info));
  memcpy(vesa_mode_info, (char*)0x14000, sizeof(struct vesa_mode_info)); // 0x14000 = 0x10000 + 0x4000 defined in boot16.S
}

/**
 * @return va Virtual address of framebuffer
 */
unsigned long do_fbmap() {
  unsigned long va = 0xe000000; // Fixed virtual address, due to the lack of address space management function
  unsigned long pa = vesa_mode_info->fbbase;
  // framebuffer area size(B), divide 8bits, convert unit to B
  int size = vesa_mode_info->hres * vesa_mode_info->vres * vesa_mode_info->bpp / 8;
  /*
  * Explanation of the calculation formula for `npage`
  * Here are three scenarios:
  * 1) if size < PAGE_SIZE then only need 1 page
  *      => (size + PAGE_SIZE - 1) / PAGE_SIZE = 1
  * 2) if size == PAGE_SIZE then only need 1 page
  *      => (PAGE_SIZE + PAGE_SIZE - 1) / PAGE_SIZE = 1
  * 3) if size > PAGE_SIZE && size < PAGE_SIZE*2 then need 2 page
  *      => (size + PAGE_SIZE - 1) / PAGE_SIZE = 2
  * 
  * Note:
  * - `+ PAGE_SIZE`: used in scenario (1), avoiding zero after integer division
  * - `- 1`        : used in scenario (2), avoid allocating an extra useless page
  */
  int npage = (size + PAGE_SIZE - 1) / PAGE_SIZE;
  /*
  * Establish process address space to framebuffer address space mapping
  * - pa = vesa_mode_info->fbbase : Allocated by BIOS/EFI when the system is powered on
  * - pyhsical page               : Establish here
  */
  map_range(current->pml4, va, pa, 0x4, npage);

  return va;
}

int do_get_mode_info(struct mode_info *mode_info) {
  mode_info->fbbase = vesa_mode_info->fbbase;
  mode_info->hres = vesa_mode_info->hres;
  mode_info->vres = vesa_mode_info->vres;
  mode_info->bpp = vesa_mode_info->bpp;

  return 0;
}